package luz.javaproxy.plugin;


import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.ServiceLoader;

import luz.javaproxy.common.Tuple;
import luz.javaproxy.config.ConfigMgr;
import luz.javaproxy.config.PluginConfig;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;


public class PluginMgr {
	private static final Log log = LogFactory.getLog(PluginMgr.class);
	
	private List<Tuple<PluginInterface, Boolean>> plugins=new LinkedList<Tuple<PluginInterface,Boolean>>();
	private List<PluginInterface> enabledPlugins=new LinkedList<PluginInterface>();

	
	private ServiceLoader<PluginInterface> loader;
	private static PluginMgr service;

	
    /**
     * Creates a new instance of DictionaryService
     */

	private PluginMgr(){
		loader = ServiceLoader.load(PluginInterface.class);
	}

    /**
     * Retrieve the singleton static instance of DictionaryService.
     */
    public static synchronized PluginMgr getInstance() {
        if (service == null) {
            service = new PluginMgr();
        }
        return service;
    }
    
	public void init(ConfigMgr cMgr){
		cMgr.setPluginMgr(this);
		PluginInterface plugin;
		String simpleClassName;
		PluginConfig pluginConfig;
		Properties pluginProperties;
		boolean pluginEnabled;
		int priorityIndex;

        Iterator<PluginInterface> iterator = loader.iterator();
        while (iterator.hasNext()) {
        	plugin = iterator.next();
        	simpleClassName=plugin.getClass().getSimpleName();
        	pluginConfig = cMgr.getPluginConfig(simpleClassName);
			pluginProperties = pluginConfig==null?new Properties():pluginConfig.getPluginConfig();
			pluginEnabled    = pluginConfig==null?false:pluginConfig.isEnabled();
			priorityIndex    = pluginConfig==null?0:pluginConfig.getPluginPriority();
            plugin.setSettings(pluginProperties);
            log.info("Plugin loaded: "+simpleClassName);
            
			if (priorityIndex>=plugins.size())
			priorityIndex=plugins.size();
				plugins.add(priorityIndex, new Tuple<PluginInterface, Boolean>(plugin, pluginEnabled));
        }

		updateEnabledPlugins();
	}
	
	
	private void updateEnabledPlugins(){
		for (Tuple<PluginInterface,Boolean> tuple : plugins) {
			if (tuple.getSecond())
				enabledPlugins.add(tuple.getFirst());
		}
	}
	
	
	public List<Tuple<PluginInterface, Boolean>> getPlugins() {
		return plugins;
	}
	
	
	public void setPluginEnabled(PluginInterface plugin, boolean enabled){
		log.info("Plugin "+(enabled?"enabled ":"disabled")+": "+plugin.getClass().getSimpleName());
		enabledPlugins.clear();
		for (Tuple<PluginInterface, Boolean> tuple : plugins) {
			if (tuple.getFirst().equals(plugin))
				tuple.setSecond(enabled);
			if (tuple.getSecond())
				enabledPlugins.add(tuple.getFirst());
		}
	}
	
	
	public int getPluginPriority(PluginInterface plugin) {
		for (int i = 0; i < plugins.size(); i++) {
			Tuple<PluginInterface, Boolean> tuple = plugins.get(i);
			if (tuple.getFirst().equals(plugin))
				return i;
		}
		return -1;
	}
	
	public int setPluginPriority(PluginInterface plugin, int priority) {
		if (priority<0)
			priority=0;
		else if (priority>=plugins.size())
			priority=plugins.size()-1;
			
			
		boolean enabled=true;
		for (Tuple<PluginInterface, Boolean> tuple : plugins) {
			if (tuple.getFirst().equals(plugin)){
				plugins.remove(tuple);
				enabled=tuple.getSecond();
				break;
			}
		}
		plugins.add(priority, new Tuple<PluginInterface, Boolean>(plugin, enabled));
		updateEnabledPlugins();
		log.info("Set priority "+priority+" to "+plugin.getClass().getSimpleName());
		return priority;
	}
	

	

	public void onRequest(final HttpRequest request) {
		for (PluginInterface plugin : enabledPlugins)
			plugin.onRequest(request);
	}
	
	public void onResponse(final HttpRequest request, final HttpResponse response) {
		for (PluginInterface plugin : enabledPlugins)
			plugin.onResponse(request, response);
	}


	public List<PluginConfig> getPluginConfigs() {
		List<PluginConfig> list = new LinkedList<PluginConfig>();
		
		
		Tuple<PluginInterface, Boolean> tuple;
		PluginInterface plugin;
		for (int i = 0; i < plugins.size(); i++) {
			tuple=plugins.get(i);
			plugin = tuple.getFirst();
			list.add(new PluginConfig(plugin.getClass().getSimpleName(), plugin.getSettings(), tuple.getSecond(), i));
		}

		return list;
	}




}
